package org.tangerinejunction.imstats.data;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.Calendar;

import org.tangerinejunction.imstats.logs.LogFile;

import prefuse.data.Graph;
import prefuse.data.Table;
import prefuse.data.tuple.TupleManager;
import prefuse.data.util.TableIterator;

/**
 * IMDataset is where we keep track of all the instant messaging data.
 * Here we keep links to all accounts, entities, log files, and any logical
 * structures we derive from the data.
 * 
 * @author meganthorsen
 */
public class IMDataset implements Externalizable
{
	private static final long serialVersionUID = -1684788250289906961L;
	
	public static Calendar lastRead;
	
	private Calendar firstDate;
	
	private Table accountTable;
	private Table entityTable;
	private Graph graph;
	private ArrayList<LogFile> logFiles;
	//private HashMap<String, Entity> entities;
	
	public IMDataset()
	{
		accountTable = new Table();
		graph = new Graph();
		accountTable.setTupleManager(new TupleManager(accountTable, graph, Account.class));
		accountTable.addColumn(TableFactory.ROW_COL_NAME, Integer.class);
		accountTable.addColumn(Account.FILTERED, Boolean.class);
		accountTable.addColumn(Account.PROTOCOL_KEY, String.class);
        accountTable.addColumn(Account.MIN_LOG_DATE, Calendar.class);
		accountTable.addColumn(Account.MY_ACCOUNT_NAME_KEY, String.class);
		accountTable.addColumn(Account.NAME_KEY, String.class);
		accountTable.addColumn(Account.ENTITY_KEY, Entity.class);
		accountTable.addColumn(Account.LOG_FILES_KEY, ArrayList.class);
		logFiles = new ArrayList<LogFile>();
		
		entityTable = new Table();
		entityTable.setTupleManager(new TupleManager(entityTable, graph, Entity.class));
		entityTable.addColumn(TableFactory.ROW_COL_NAME, Integer.class);
		entityTable.addColumn(Entity.FILTERED, Boolean.class);
		entityTable.addColumn(Entity.NAME_KEY, String.class);
		entityTable.addColumn(Entity.ACCOUNTS_KEY, AccountSet.class);
		//entities = new HashMap<String,Entity>();
		
		firstDate = Calendar.getInstance();
	}

	/**
	 * 
	 * @param account	the Account to add to the dataset
	 */
	public void addAccount(Account account)
	{
		accountTable.addTuple(account);
	}

	/**
	 * 
	 * @param logFile	the LogFile to add to the dataset
	 */
	public void addLogFile(LogFile logFile)
	{
		int fileIndex = findLogFile(logFile);
		if (fileIndex < 0)
			logFiles.add(logFile);
		else
			logFiles.set(fileIndex, logFile);
		if (logFile.getDate().before(firstDate))
			firstDate = logFile.getDate();
	}
	
	/**
	 * 
	 * @param targetFile	the LogFile we want to find
	 * @return	the index of the LogFile if found; -1 if not found
	 */
	protected int findLogFile(LogFile targetFile)
	{
		for (LogFile file : logFiles)
		{
			if (file.getAbsolutePath().equals(targetFile.getAbsolutePath()))
				return logFiles.indexOf(file);
		}
		return -1;
	}
	
	/**
	 * 
	 * @return	the starting date of the dataset
	 */
	public Calendar getFirstDate()
	{
		return firstDate;
	}
	
	/**
	 * 
	 * @return	the Prefuse Table backing the Accounts
	 */
	public Table getAccountTable()
	{
		return accountTable;
	}
	
	/**
	 * 
	 * @return	the Prefuse Table backing the Entities
	 */
	public Table getEntityTable()
	{
		return entityTable;
	}
	
	/**
	 * 
	 * @return	the list of all LogFiles in the dataset
	 */
	public ArrayList<LogFile> getLogFiles()
	{
		return logFiles;
	}
	
	/**
	 * 
	 * @return	the Prefuse Graph backing this dataset
	 */
	public Graph getGraph()
	{
		return graph;
	}
	
	/**
	 * 
	 * @param name	the name of the Entity to which we want to add the Account
	 * @param account	the Account we want to add
	 */
	public void addAccountToEntityByName(String name, Account account)
	{
		if (account.getEntity() != null)
		{
			Entity oldEntity = account.getEntity();
			oldEntity.removeAccount(account);
			if (oldEntity.getAccounts().size() == 0)
				entityTable.removeTuple(oldEntity);
		}
		Entity e = getEntityByName(name);
		if (e != null)
		{
			e.addAccount(account);
		}
		else
		{
			Entity entity = new Entity();
			entity.init(entityTable, graph, entityTable.addRow(), name);
			entity.addAccount(account);
			//entities.put(name, entity);
		}
	}
	
	/**
	 * 
	 * @param name	the name of the Account we want to retrieve
	 * @return	the Account of the name provided
	 */
	public Account getAccountByName(String name)
	{
		TableIterator it = accountTable.iterator();
		while (it.hasNext())
		{
			Integer row = (Integer)it.next();
			Account account = (Account)accountTable.getTuple(row);
			if (account.getName().equals(name))
				return account;
		}
		return null;
	}
	
	/**
	 * 
	 * @param name	the name of the Entity we want to retrieve
	 * @return	the Entity of the name provided
	 */
	public Entity getEntityByName(String name)
	{
		TableIterator it = entityTable.iterator();
		while (it.hasNext())
		{
			Integer row = (Integer)it.next();
			Entity entity = (Entity)entityTable.getTuple(row);
			if (entity.getName().equals(name))
				return entity;
		}
		return null;
	}

	public void readExternal(ObjectInput in) throws IOException,
			ClassNotFoundException 
	{
		//entityTable = (Table)in.readObject();
	}

	public void writeExternal(ObjectOutput out) throws IOException 
	{
		//out.writeObject(entityTable);
		//
		/*
		for (int row = 0; row < entityTable.getRowCount(); row++)
		{
			Entity entity = (Entity)entityTable.getTuple(row);
			out.writeObject(entity);
		}
		*/
	}
}
